# Copyright (c) 2024 Huawei Technologies Co., Ltd.
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This code is inspired by the pytorch's torchtune library.
# https://github.com/pytorch/torchtune
#
# openMind is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
#          http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
import argparse
import os
import yaml


def _trans_args_list_to_dict(args_list: list) -> dict:

    if len(args_list) % 2 != 0:
        raise ValueError(f"arguments in CLI should be specified in paris, but got {args_list}")

    args_dict = {}

    for idx in range(0, len(args_list), 2):
        key = args_list[idx]
        val = args_list[idx + 1]

        if not key.startswith("--"):
            raise ValueError(f"Argument name `{key}` in CLI should start with `--`")

        if val.startswith("--"):
            raise ValueError(f"Argument value `{val}` of key `{key}` in CLI should not start with `--`")

        args_dict[key.lstrip("-")] = val

    return args_dict


def str2bool(value):

    if isinstance(value, bool):
        return value
    if value.lower() in {"true", "1"}:
        return True
    elif value.lower() in {"false", "0"}:
        return False
    else:
        raise argparse.ArgumentTypeError("Boolean value expected.")


def str2bool_or_auto(value):
    if isinstance(value, bool):
        return value
    value = value.lower()
    if value in {"true", "yes", "1"}:
        return True
    elif value in {"false", "no", "0"}:
        return False
    elif value == "auto":
        return "auto"
    else:
        raise argparse.ArgumentTypeError("Value should be one of: 'true', 'false', or 'auto'.")


def safe_load_yaml(path):
    if path is None:
        raise ValueError("param `path` is required for `safe_load_yaml` func.")

    if not isinstance(path, str):
        raise TypeError(f"param `path` should be string format for `safe_load_yaml func`, but got {type(path)} type.")

    if not os.path.exists(path):
        raise FileNotFoundError(f"yaml file path {path} does not exist.")

    path = os.path.realpath(path)

    if not path.endswith(".yaml") and not path.endswith(".yml"):
        raise ValueError(f"path {path} is not a yaml/yml file path.")

    with open(path, "r") as file:
        content = yaml.safe_load(file)

    return content
